package se.webbzon.boltzmann.game.character;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import se.webbzon.boltzmann.loader.Loader;
import se.webbzon.boltzmann.loader.LoaderException;
import se.webbzon.boltzmann.loader.LoaderUtilityPointer;
import se.webbzon.oschi01.filenameparser.FilenameParser;
import se.webbzon.oschi01.resourceset.ResourceSet;
import se.webbzon.oschi01.resourceset.ResourceSetLoaderException;
import se.webbzon.oschi01.textureset.Texture3D;
import se.webbzon.oschi01.textureset.Texture3DSetLoader;

public class CharacterLoader implements Loader {
	
	// A collection of resource names related to this loader
	private final static Collection<String> resourceNames = new ArrayDeque<String>();
	
	static {
		resourceNames.add("character");
		resourceNames.add("characterAction");
	}
	
	// The map to store the character texture sets in
	private final Map<String,AbstractCharacterTextureSet> resourceTable;
	
	// A map containing unmapped character actions
	private final Map<String,LoadedCharacterAction> unmappedActions;
	
	/*============================================================
	Constructors
	============================================================*/
	
	/** Creates a new CharacterTextureSetLoader which loads character texture sets
	 * into a map. The key to the map is given by the character attribute <name> **/
	public CharacterLoader(Map<String,AbstractCharacterTextureSet> resourceTable) {
		this.resourceTable = resourceTable;
		this.unmappedActions = new HashMap<String,LoadedCharacterAction>();
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	@Override public String getCategory() {
		return "characters";
	}

	@Override public Collection<String> getSupportedResources() {
		return resourceNames;
	}

	@Override public void load(LoaderUtilityPointer pointer, String resourceName,
			Map<String, String> resourceMap) throws LoaderException {
		if (resourceName.equals("character"))
			loadCharacter(pointer, resourceMap);
		else
			loadCharacterAction(pointer, resourceMap);
	}
	
	/*============================================================
	Private Methods
	============================================================*/
	
	/** Loads a new character into the resource table. **/
	private void loadCharacter(	LoaderUtilityPointer pointer,
								Map<String, String> resourceMap) 
										throws LoaderException {
		Set<Map.Entry<String, String>> entries = resourceMap.entrySet();
		// Create new character texture set
		LoadedCharacterTextureSet characterTextureSet = new LoadedCharacterTextureSet();
		for (Map.Entry<String, String> entry : entries) {
			// Iterate over the map
			final String key = entry.getKey();
			final String value = entry.getValue();
			if (key.equals("name")) {
				// Add the character texture set to the resource table
				//if (resourceTable.containsKey(value))
					//throw new LoaderException(
						//"Name collision occurred when loading CharacterTextureSet \"" +
						//value + "\" from " + resourceURI);
				resourceTable.put(value,characterTextureSet);
			} else {
				LoadedCharacterAction unmappedAction = unmappedActions.get(value);
				if (unmappedAction == null) {
					// Create a new unmapped action and add to unmapped actions
					unmappedAction = new LoadedCharacterAction();
					unmappedActions.put(value, unmappedAction);
				}
				// Add the action to the unmapped action set
				characterTextureSet.addAction(CharacterActionEnum.valueOf(key.toUpperCase()),unmappedAction);
			}
		}
	}
	
	/** Loads a new character action into an existing character texture set. **/
	private void loadCharacterAction(	LoaderUtilityPointer pointer,
										Map<String, String> resourceMap) throws LoaderException {
		//final String name = resourceMap.get("name");
		// Check if the character action has a name
		//if (name == null)
			//throw new LoaderException("Cannot load unnamed character action from " + resourceURI);
		final LoadedCharacterAction action = unmappedActions.get(resourceMap.get("name"));
		// Check if the action is associated with any character actions
		//if (action == null)
			//throw new LoaderException("Cannot load character action before character in " + resourceURI);
		
		Set<Map.Entry<String, String>> entries = resourceMap.entrySet();
		for (Map.Entry<String, String> entry : entries) {
			final String key = entry.getKey();
			final String value = entry.getValue();
			if (key.equals("textureSpeed"))
				action.setTextureSpeed(Double.parseDouble(value));
			else if (	key.equals("leftUp") || key.equals("leftDown") ||
						key.equals("rightUp") || key.equals("rightDown"))
				loadAction(pointer,action,key,value);
		}
	}
	
	/** Loads a texture set into an action with a given name. **/
	private void loadAction(LoaderUtilityPointer pointer, LoadedCharacterAction action, 
							String facing, String expression) 
									throws LoaderException {
		Texture3DSetLoader tsl = new Texture3DSetLoader();
		Collection<String> filenames = FilenameParser.parse(expression);
		try {
			for (String filename : filenames) {
				tsl.addFromURL(new URL(pointer.getXMLURL(),filename));
			}
			final ResourceSet<Texture3D> textureSet = tsl.getResourceSet();
			if (facing.equals("leftUp"))
				action.setLeftUp(textureSet);
			else if (facing.equals("leftDown"))
				action.setLeftDown(textureSet);
			else if (facing.equals("rightDown"))
				action.setRightDown(textureSet);
			else
				action.setRightUp(textureSet);
		} catch (MalformedURLException | ResourceSetLoaderException e) {
			throw new LoaderException(e);
		}
	}

}
